// Copyright (c) 2023 CHANGLEI. All rights reserved.

import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter_grasp/flutter_grasp.dart';

/// Created by changlei on 2020-02-13.
///
/// 对[SupportCustomScrollView]的简单封装
class SupportListView extends StatelessWidget {
  /// 构造函数
  SupportListView({
    super.key,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.controller,
    this.primary,
    this.physics,
    this.shrinkWrap = false,
    this.padding,
    double? itemExtent,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    this.cacheExtent,
    List<Widget> children = const <Widget>[],
    this.semanticChildCount,
    this.dragStartBehavior = DragStartBehavior.start,
    this.loadOptionsBuilder = const DefaultLoadOptionsBuilder(),
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    this.loadNextBuilder = SupportCustomScrollView.buildLoadNext,
    this.loadNextSliverBuilder,
    this.placeholderBuilder = SupportCustomScrollView.buildPlaceholder,
    this.placeholderSliverBuilder,
    this.restorationId,
    this.clipBehavior = Clip.hardEdge,
    this.center,
    this.anchor = 0.0,
    this.scrollBehavior,
  }) : _sliverListView = SliverListView(
          padding: EdgeInsets.zero,
          itemExtent: itemExtent,
          addAutomaticKeepAlives: addAutomaticKeepAlives,
          addRepaintBoundaries: addRepaintBoundaries,
          addSemanticIndexes: addSemanticIndexes,
          scrollDirection: scrollDirection,
          children: children,
        );

  /// builder构造函数
  SupportListView.builder({
    super.key,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.controller,
    this.primary,
    this.physics,
    this.shrinkWrap = false,
    this.padding,
    double? itemExtent,
    required IndexedWidgetBuilder itemBuilder,
    int? itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    this.cacheExtent,
    this.semanticChildCount,
    this.dragStartBehavior = DragStartBehavior.start,
    this.loadOptionsBuilder = const DefaultLoadOptionsBuilder(),
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    this.loadNextBuilder = SupportCustomScrollView.buildLoadNext,
    this.loadNextSliverBuilder,
    this.placeholderBuilder = SupportCustomScrollView.buildPlaceholder,
    this.placeholderSliverBuilder,
    this.restorationId,
    this.clipBehavior = Clip.hardEdge,
    this.center,
    this.anchor = 0.0,
    this.scrollBehavior,
  })  : assert(itemCount == null || itemCount >= 0),
        assert(semanticChildCount == null || semanticChildCount <= itemCount!),
        _sliverListView = SliverListView.builder(
          itemBuilder: itemBuilder,
          itemCount: itemCount,
          padding: EdgeInsets.zero,
          itemExtent: itemExtent,
          addAutomaticKeepAlives: addAutomaticKeepAlives,
          addRepaintBoundaries: addRepaintBoundaries,
          addSemanticIndexes: addSemanticIndexes,
          scrollDirection: scrollDirection,
        );

  /// 分割器
  SupportListView.separated({
    super.key,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.controller,
    this.primary,
    this.physics,
    this.shrinkWrap = false,
    this.padding,
    required IndexedWidgetBuilder itemBuilder,
    required IndexedWidgetBuilder separatorBuilder,
    required int itemCount,
    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    this.cacheExtent,
    this.loadOptionsBuilder = const DefaultLoadOptionsBuilder(),
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    this.loadNextBuilder = SupportCustomScrollView.buildLoadNext,
    this.loadNextSliverBuilder,
    this.placeholderBuilder = SupportCustomScrollView.buildPlaceholder,
    this.placeholderSliverBuilder,
    this.restorationId,
    this.clipBehavior = Clip.hardEdge,
    this.center,
    this.anchor = 0.0,
    this.scrollBehavior,
  })  : assert(itemCount >= 0),
        semanticChildCount = null,
        dragStartBehavior = DragStartBehavior.start,
        _sliverListView = SliverListView.separated(
          itemBuilder: itemBuilder,
          separatorBuilder: separatorBuilder,
          itemCount: itemCount,
          padding: EdgeInsets.zero,
          addAutomaticKeepAlives: addAutomaticKeepAlives,
          addRepaintBoundaries: addRepaintBoundaries,
          addSemanticIndexes: addSemanticIndexes,
          scrollDirection: scrollDirection,
        );

  /// 自定义
  SupportListView.custom({
    super.key,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.controller,
    this.primary,
    this.physics,
    this.shrinkWrap = false,
    this.padding,
    double? itemExtent,
    required SliverChildDelegate childrenDelegate,
    this.cacheExtent,
    this.semanticChildCount,
    this.dragStartBehavior = DragStartBehavior.start,
    this.loadOptionsBuilder = const DefaultLoadOptionsBuilder(),
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
    this.loadNextBuilder = SupportCustomScrollView.buildLoadNext,
    this.loadNextSliverBuilder,
    this.placeholderBuilder = SupportCustomScrollView.buildPlaceholder,
    this.placeholderSliverBuilder,
    this.restorationId,
    this.clipBehavior = Clip.hardEdge,
    this.center,
    this.anchor = 0.0,
    this.scrollBehavior,
  }) : _sliverListView = SliverListView.custom(
          padding: EdgeInsets.zero,
          itemExtent: itemExtent,
          childrenDelegate: childrenDelegate,
          scrollDirection: scrollDirection,
        );

  /// {@template flutter.widgets.scroll_view.controller}
  /// An object that can be used to control the position to which this scroll
  /// view is scrolled.
  ///
  /// Must be null if [primary] is true.
  ///
  /// A [ScrollController] serves several purposes. It can be used to control
  /// the initial scroll position (see [ScrollController.initialScrollOffset]).
  /// It can be used to control whether the scroll view should automatically
  /// save and restore its scroll position in the [PageStorage] (see
  /// [ScrollController.keepScrollOffset]). It can be used to read the current
  /// scroll position (see [ScrollController.offset]), or change it (see
  /// [ScrollController.animateTo]).
  /// {@endtemplate}
  final ScrollController? controller;

  /// 滚动方向
  final Axis scrollDirection;

  /// 是否翻转
  final bool reverse;

  /// 是否使用[PrimaryScrollController]
  final bool? primary;

  /// 插值器，可以自定义滚动效果
  final ScrollPhysics? physics;

  /// 是否压缩包裹
  final bool shrinkWrap;

  /// 内边距
  final EdgeInsetsGeometry? padding;

  /// 缓存区域
  final double? cacheExtent;

  /// childCount
  final int? semanticChildCount;

  /// {@macro flutter.widgets.scrollable.dragStartBehavior}
  final DragStartBehavior dragStartBehavior;

  /// 加载配置
  final SliverListView _sliverListView;

  /// 加载配置
  final LoadOptionsBuilder loadOptionsBuilder;

  /// {@template flutter.widgets.scroll_view.keyboardDismissBehavior}
  /// [ScrollViewKeyboardDismissBehavior] the defines how this [ScrollView] will
  /// dismiss the keyboard automatically.
  /// {@endtemplate}
  final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;

  /// 上拉加载更多配置
  final LoadNextBuilder loadNextBuilder;

  /// 上拉加载更多配置
  final LoadNextSliverBuilder? loadNextSliverBuilder;

  /// 占位图
  final PlaceholderBuilder placeholderBuilder;

  /// 占位图
  final PlaceholderSliverBuilder? placeholderSliverBuilder;

  /// {@macro flutter.widgets.scrollable.restorationId}
  final String? restorationId;

  /// {@macro flutter.material.Material.clipBehavior}
  ///
  /// Defaults to [Clip.hardEdge].
  final Clip clipBehavior;

  /// The first child in the [GrowthDirection.forward] growth direction.
  ///
  /// Children after [center] will be placed in the [AxisDirection] determined
  /// by [scrollDirection] and [reverse] relative to the [center]. Children
  /// before [center] will be placed in the opposite of the axis direction
  /// relative to the [center]. This makes the [center] the inflection point of
  /// the growth direction.
  ///
  /// The [center] must be the key of one of the slivers built by [buildSlivers].
  ///
  /// Of the built-in subclasses of [ScrollView], only [CustomScrollView]
  /// supports [center]; for that class, the given key must be the key of one of
  /// the slivers in the [CustomScrollView.slivers] list.
  ///
  /// See also:
  ///
  ///  * [anchor], which controls where the [center] as aligned in the viewport.
  final Key? center;

  /// {@template flutter.widgets.scroll_view.anchor}
  /// The relative position of the zero scroll offset.
  ///
  /// For example, if [anchor] is 0.5 and the [AxisDirection] determined by
  /// [scrollDirection] and [reverse] is [AxisDirection.down] or
  /// [AxisDirection.up], then the zero scroll offset is vertically centered
  /// within the viewport. If the [anchor] is 1.0, and the axis direction is
  /// [AxisDirection.right], then the zero scroll offset is on the left edge of
  /// the viewport.
  /// {@endtemplate}
  final double anchor;

  /// {@macro flutter.widgets.shadow.scrollBehavior}
  ///
  /// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit
  /// [ScrollPhysics] is provided in [physics], it will take precedence,
  /// followed by [scrollBehavior], and then the inherited ancestor
  /// [ScrollBehavior].
  final ScrollBehavior? scrollBehavior;

  bool get _hasElements => (_sliverListView.estimatedChildCount ?? 0) > 0;

  @override
  Widget build(BuildContext context) {
    return SupportCustomScrollView.builder(
      builder: loadOptionsBuilder,
      controller: controller,
      scrollDirection: scrollDirection,
      reverse: reverse,
      primary: primary,
      physics: physics,
      shrinkWrap: shrinkWrap,
      cacheExtent: cacheExtent,
      semanticChildCount: semanticChildCount,
      dragStartBehavior: dragStartBehavior,
      padding: padding,
      hasElements: _hasElements,
      keyboardDismissBehavior: keyboardDismissBehavior,
      loadNextBuilder: loadNextBuilder,
      loadNextSliverBuilder: loadNextSliverBuilder,
      placeholderBuilder: placeholderBuilder,
      placeholderSliverBuilder: placeholderSliverBuilder,
      restorationId: restorationId,
      clipBehavior: clipBehavior,
      anchor: anchor,
      center: center,
      scrollBehavior: scrollBehavior,
      slivers: <Widget>[
        _sliverListView,
      ],
    );
  }
}
